package btb.ui;

import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;

import com.esotericsoftware.minlog.Log;

import btb.engine.CDisplayTask;
import btb.util.CGuiUtils;

import de.matthiasmann.twl.Button;
import de.matthiasmann.twl.EditField;
import de.matthiasmann.twl.GUI;
import de.matthiasmann.twl.Label;
import de.matthiasmann.twl.ListBox;
import de.matthiasmann.twl.TextArea;
import de.matthiasmann.twl.Widget;
import de.matthiasmann.twl.textarea.SimpleTextAreaModel;
import de.matthiasmann.twl.theme.ThemeManager;

public abstract class AGuiObject extends Widget
{
	protected static final String BTB_THEME_02_FILEPATH = "../../resources/graphics/btb_theme_02.xml";
	
	protected static final int DEFAULT_WINDOW_WIDTH = 1200; // [Development]: Maintain width to height ratio of 4:3
	protected static final int DEFAULT_WINDOW_HEIGHT = 900;
	
	public static final int DISPLAY_OPT_NONE 		= -1;
	
	public boolean guiInitialized;
	public boolean quit;
	public int guiIterator;
	
	protected CDisplayTask callingTask;
	protected GUI gui;
	protected ThemeManager theme;
	
	public AGuiObject(CDisplayTask _parent)
	{
		this.callingTask = _parent;
		initializeWidgets(DISPLAY_OPT_NONE);
		addWidgets(DISPLAY_OPT_NONE);
		guiInitialized = false;
		guiIterator = 0;
	}
	
	public AGuiObject(CDisplayTask _parent, int _guiDisplayOption)
	{
		this.callingTask = _parent;
		initializeWidgets(_guiDisplayOption);
		addWidgets(_guiDisplayOption);
		guiInitialized = false;
		guiIterator = 0;
	}
	
	public abstract void initializeGUI(int _guiDisplayOption);
	protected abstract void initializeWidgets(int _guiDisplayOption);
	protected abstract void addWidgets(int _guiDisplayOption);
	protected abstract void setLayout(int _guiDisplayOption);
	protected abstract void resetPage(int _guiDisplayOption);
	protected abstract void removeCallBacks(int _guiDisplayOption);
	protected abstract void addCallBacks(int _guiDisplayOption);
	
	public void invoke()
	{	
		// [Note]: Main loop of the GUI component. gui.update() renders the controls using OpenGL, Display.update() tells LWJGL to update
		// the screen. ReduceInputLag tells LWJGL to process messages and poll the mouse and keyboard.
		try
		{
			if(!Display.isCloseRequested() && !this.quit)
			{
				GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
				
				gui.update();
				Display.update();
				CGuiUtils.reduceInputLag();
			}
		}
		catch( Exception ex )
		{
			CGuiUtils.errMsg(ex);
		}
	}
	
	public void dismiss()
	{
		try
		{
			this.guiInitialized = false;
			
			// [Note]: Not even sure if these destroy() calls are needed or not. *shrug*
			//this.gui.destroy();
			//this.theme.destroy();
		}
		catch(Exception ex)
		{
			CGuiUtils.errMsg(ex);
		}
	}
	
	protected void initializeDisplay(int _winWidth, int _winHeight, String _displayTitle, String _themeFilePath, int _guiDisplayOption)
	{
		if(!this.guiInitialized)
		{
			try
			{	
				guiIterator++;
				
				if(guiIterator <= 1)
				{
					if(Log.INFO) Log.info("", "");
					gui = new GUI(this, callingTask.renderer );
				}
				else
				{
					resetPage(_guiDisplayOption);
				}
				
				// [Note]: Relative file paths start from "workspace/btb_gui_test/bin/btb_gui" - that is, the folder containing the .class files
				// At least, this is true while developing on Portable Eclipse on G:\"
				theme = ThemeManager.createThemeManager(CGuiLogin.class.getResource(_themeFilePath), callingTask.renderer);
				gui.applyTheme(theme);
				
				// [Note]: In this step, buttons and other widget objects are created and added as children to the main GUI component.
				removeCallBacks(_guiDisplayOption);
				addCallBacks(_guiDisplayOption);
				setLayout(_guiDisplayOption);
			}
			catch( Exception ex )
			{
				CGuiUtils.errMsg(ex);
			}
			
			this.guiInitialized = true;
		}
	}
	
	protected void addNewLabel(Label _obj, String _themeName, String _defaultText)
	{
		if(_defaultText != null)
			_obj.setText(_defaultText);
		addNewWidget(_obj, _themeName);
	}
	
	protected void addNewEditField(EditField _obj, String _themeName, String _defaultText)
	{
		if(_defaultText != null)
			_obj.setText(_defaultText);
		addNewWidget(_obj, _themeName);
	}
	
	protected void addNewButton(Button _obj, String _themeName, String _defaultText)
	{
		if(_defaultText != null)
			_obj.setText(_defaultText);
		addNewWidget(_obj, _themeName);
	}
	
	protected void addNewPasswordField(EditField _obj, String _themeName, String _defaultText, char passwordChar )
	{
		_obj.setPasswordChar( '*' );
		_obj.setPasswordMasking( true );
		
		if(_defaultText != null)
			_obj.setText(_defaultText);
				
		addNewWidget(_obj, _themeName);
	}
	
	protected void addNewTextArea(TextArea _obj, String _themeName, String _defaultText, SimpleTextAreaModel _model)
	{		
		if(_model != null)
		{
			_obj.setModel(_model);
			_model.setText(_defaultText);
		}
			
		addNewWidget(_obj, _themeName);
	}
	
	@SuppressWarnings("rawtypes")
	protected void addNewListBox(ListBox _obj, String _themeName)
	{
		addNewWidget(_obj, _themeName);
	}
	
	protected void addNewWidget(Widget _obj, String _themeName)
	{
		_obj.setTheme(_themeName);
		add(_obj);
	}
	
	protected void updateTextWidget(SimpleTextAreaModel _txtModel, String _str)
	{
		_txtModel.setText(_str);
	}
	
	protected void resizeWidget(Widget _obj, int width, int height)
	{
		_obj.setSize( width, height);
	}
	
	protected void resizeWidgetRelativeToWindow(Widget _obj, float winWidthFactor, float winHeightFactor, boolean checkMaxDimensions)
	{
		int w, h;
		int winWidth = Display.getDisplayMode().getWidth(), winHeight = Display.getDisplayMode().getHeight();
		
		if(checkMaxDimensions)
		{
			w = (int) Math.min(winWidthFactor * winWidth, _obj.getMaxWidth());
			h = (int) Math.min(winHeightFactor * winHeight, _obj.getMaxHeight());
		}
		else
		{
			w = (int) (winWidthFactor * winWidth);
			h = (int) (winHeightFactor * winHeight);
		}
		
		_obj.setSize(w, h);
	}
	
	protected void copyWidgetSize(Widget _src, Widget _dest)
	{
		_dest.setSize(_src.getWidth(), _src.getHeight());
	}
	
	protected void placeWidget(Widget _obj, int x, int y)
	{
		_obj.setPosition(x, y);
	}
	
	protected void placeWidgetAgainstWindow(Widget _obj, float _xFactor, float _yFactor, boolean _adjustX, boolean _adjustY)
	{
		int winWidth = Display.getDisplayMode().getWidth(), winHeight = Display.getDisplayMode().getHeight();
		int x, y;
		
		x = (int)(_xFactor * winWidth);
		if(_adjustX)
			x -= (_obj.getWidth() / 2);
		y = (int)(_yFactor * winHeight);
		if(_adjustY)
			y -= (_obj.getHeight() / 2);
		
		_obj.setPosition(x, y);
	}
	
	protected void placeWidgetInTightRow(Widget _obj, Widget _previousObj, int _pos, int _totalWidth, float _widthFactor, float _y, boolean _yIsFactor)
	{
		int winWidth = Display.getDisplayMode().getWidth(), winHeight = Display.getDisplayMode().getHeight();
		int x, y;
		
		if(_yIsFactor)
		{
			y = (int) (_y * winHeight);
		}
		else
		{
			if(_y >= 0)
				y = (int) _y;
			else
				y = 0;
		}
		
		if(_obj != null)
		{
			if(_pos == 1)
			{
				x = (int) ((winWidth - _totalWidth ) * _widthFactor);
				
				_obj.setPosition(x, y);
			}
			else if(_pos > 1)
			{
				placeWidgetOnRightOf(_obj, _previousObj, y);
			}
		}
	}
	
	protected void placeWidgetOnRightOf(Widget _obj, Widget _leftObj, int _y)
	{
		int x, y;
		
		if(_leftObj != null && _obj != null)
		{
			x = _leftObj.getX() + _leftObj.getWidth();
			if(_y >= 0)
				y = _y;
			else
				y = _leftObj.getY();
			
			_obj.setPosition(x, y);
		}
	}
		
	protected void centerWidgetX(Widget _obj, float _y, boolean _yIsFactor)
	{
		int winWidth = Display.getDisplayMode().getWidth(), winHeight = Display.getDisplayMode().getHeight();
		int x, y;
		
		if(_obj != null)
		{
			x = ( winWidth - _obj.getWidth() ) / 2;
			
			if(_yIsFactor)
			{
				y = (int) (_y * winHeight);
			}
			else
			{
				if(_y >= 0)
					y = (int) _y;
				else
					y = 0;
			}
			
			_obj.setPosition(x, y);
		}
		
	}
	
	protected void placeWidgetInEqualRow(Widget _obj, int _pos, int _numWidgets, float _y, boolean _yIsFactor)
	{
		int winWidth = Display.getDisplayMode().getWidth(), winHeight = Display.getDisplayMode().getHeight();
		int x, y;
		
		if(_obj != null)
		{
			x = _pos * ( winWidth - ( _obj.getWidth() * _numWidgets ) ) / (_numWidgets + 1) + ((_pos - 1) * _obj.getWidth());
			
			if(_yIsFactor)
				y = (int) (_y * winHeight);
			else
				y = (int) _y;
			
			_obj.setPosition(x, y);
		}
	}
}
